package com.feature.shop.user.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.feature.core.domain.PageVo;
import com.feature.core.mybatis.BaseService;
import com.feature.core.mybatis.SmartBaseMapper;
import com.feature.core.util.AssertUtil;
import com.feature.shop.auth.api.vo.LoginUserVo;
import com.feature.shop.user.api.enums.ShopMenuTypeEnum;
import com.feature.shop.user.api.request.AddMenuRequest;
import com.feature.shop.user.api.request.DelMenuRequest;
import com.feature.shop.user.api.request.ShopMenuListRequest;
import com.feature.shop.user.api.request.ShopMenuPageRequest;
import com.feature.shop.user.api.request.UpdateMenuRequest;
import com.feature.shop.user.api.vo.ShopMenuVo;
import com.feature.shop.user.api.vo.ShopTreeMenuVo;
import com.feature.shop.user.converter.ShopMenuConverter;
import com.feature.shop.user.mapper.ShopAuthMapper;
import com.feature.shop.user.mapper.ShopMenuMapper;
import com.feature.shop.user.mapper.ShopRoleAuthMapper;
import com.feature.shop.user.model.entity.ShopAuthEntity;
import com.feature.shop.user.model.entity.ShopMenuEntity;
import com.feature.shop.user.model.entity.ShopRoleAuthEntity;
import com.feature.shop.user.util.AuthUtil;

/***
 * 菜单表Service
 */
@Service
public class ShopMenuService extends BaseService<ShopMenuEntity> {
    @Autowired
    private ShopMenuMapper shopMenuMapper;
    @Autowired
    private ShopMenuConverter shopMenuConverter;
    @Autowired
    private ShopAuthMapper shopAuthMapper;
    @Autowired
    private ShopAuthService shopAuthService;
    @Autowired
    private ShopRoleAuthMapper shopRoleAuthMapper;

    @Override
    public SmartBaseMapper<ShopMenuEntity> getSmartBaseMapper() {
        return shopMenuMapper;
    }

    public PageVo<ShopMenuVo> findPageList(ShopMenuPageRequest req) {
        PageVo<ShopMenuEntity> pageData = shopMenuMapper.selectPageList(req.getCurPage(), req.getPageSize(), shopMenuConverter.pageRequestToQuery(req));
        PageVo<ShopMenuVo> vo = PageVo.of(pageData, shopMenuConverter::entityListToVO);
        return vo;

    }

    public List<ShopMenuVo> findList(ShopMenuListRequest req) {
        List<ShopMenuEntity> list = shopMenuMapper.selectList(shopMenuConverter.listRequestToQuery(req));
        return shopMenuConverter.entityListToVO(list);
    }

    @Override
    public Class<ShopMenuEntity> getEntityClass() {
        return ShopMenuEntity.class;
    }

    public List<ShopTreeMenuVo> getAuthMenuList(LoginUserVo loginUser) {
        List<ShopMenuEntity> list = shopMenuMapper.selectList().stream().filter(v -> ShopMenuTypeEnum.MENU.getId().equals(v.getType()))
                .filter(v -> AuthUtil.hasAuth(v.getMenuPath(), loginUser.getUser().getAuths())).collect(Collectors.toList());
        return buildHierarchyMenu(list);
    }

    public List<ShopTreeMenuVo> getMenuTreeList(LoginUserVo loginUser) {
        List<ShopMenuEntity> list = shopMenuMapper.selectList().stream().collect(Collectors.toList());
        return buildHierarchyMenu(list);
    }

    private List<ShopTreeMenuVo> buildHierarchyMenu(List<ShopMenuEntity> list) {
        Map<Integer, ShopTreeMenuVo> menuCache = list.stream().map(shopMenuConverter::entityToTreeMenuVO).collect(Collectors.toMap(ShopTreeMenuVo::getId, Function.identity()));
        List<ShopTreeMenuVo> res = new ArrayList<ShopTreeMenuVo>();
        for (ShopTreeMenuVo vo : menuCache.values()) {
            ShopTreeMenuVo parent = menuCache.get(vo.getParentMenuId());
            if (parent != null) {
                parent.getChildren().add(vo);
            } else {
                res.add(vo);
            }
        }
        return res;
    }

    public Map<String, Boolean> getUserMenuAuth(Integer userId) {
        return null;
    }

    public Integer addMenu(AddMenuRequest addMenuRequest, LoginUserVo loginUser) {
        // 验证菜单是否存在
        ShopMenuEntity query = new ShopMenuEntity();
        query.setMenuPath(addMenuRequest.getMenuPath());
        long count = shopMenuMapper.selectCount(query);
        AssertUtil.isTrue(count == 0, "菜单路径已经存在");
        // 获取父菜单
        int sep = addMenuRequest.getMenuPath().trim().lastIndexOf("/");
        Set<String> authPathSet = new HashSet<>();
        ShopMenuEntity parent = null;
        if (sep > 0) {
            ShopMenuEntity parentQuery = new ShopMenuEntity();
            parentQuery.setMenuPath(addMenuRequest.getMenuPath().substring(0, sep));
            parent = shopMenuMapper.getOne(parentQuery);
            AssertUtil.notNull(parent, "父菜单不存在");
            authPathSet.add(parent.getMenuPath());
        }
        ShopMenuEntity entity = new ShopMenuEntity();
        entity.setCreateUser(loginUser.getUser().getId());
        entity.setMenuIcon(addMenuRequest.getMenuIcon());
        entity.setMenuName(addMenuRequest.getMenuName());
        entity.setMenuPath(addMenuRequest.getMenuPath());
        entity.setParentMenuId(parent != null ? parent.getId() : 0);
        entity.setType(addMenuRequest.getType());
        entity.setUpdateUser(loginUser.getUser().getId());
        shopMenuMapper.insert(entity);
        authPathSet.add(entity.getMenuPath());
        // 添加权限
        LambdaQueryWrapper<ShopAuthEntity> queryWrapper = Wrappers.lambdaQuery(ShopAuthEntity.class).in(ShopAuthEntity::getPath, authPathSet);
        List<ShopAuthEntity> authList = shopAuthMapper.selectList(queryWrapper);
        if (!authList.isEmpty()) {
            authPathSet.removeAll(authList.stream().map(ShopAuthEntity::getPath).toList());
        }
        if (!authPathSet.isEmpty()) {
            for (String authPath : authPathSet) {
                ShopAuthEntity auth = new ShopAuthEntity();
                auth.setCreateUser(loginUser.getUser().getId());
                auth.setPath(authPath);
                auth.setUpdateUser(loginUser.getUser().getId());
                shopAuthMapper.insert(auth);
            }
        }
        return entity.getId();
    }

    public void updateMenu(UpdateMenuRequest req, LoginUserVo loginUser) {
        // 获取菜单
        ShopMenuEntity query = new ShopMenuEntity();
        query.setId(req.getMenuId());
        ShopMenuEntity menu = shopMenuMapper.getOne(query);
        AssertUtil.notNull(menu, "菜单不存在");
        ShopMenuEntity update = new ShopMenuEntity();
        update.setId(req.getMenuId());
        update.setMenuIcon(StringUtils.defaultString(req.getMenuIcon()));
        if (StringUtils.isNotBlank(req.getMenuName())) {
            update.setMenuName(req.getMenuName());
        }
        update.setUpdateUser(loginUser.getUser().getId());
        shopMenuMapper.updateById(update);
    }

    public void delMenu(DelMenuRequest req, LoginUserVo loginUser) {
        ShopMenuEntity menu = shopMenuMapper.selectById(req.getMenuId());
        if (menu == null) {
            return;
        }
        shopMenuMapper.deleteById(req.getMenuId());
        // 删除权限
        ShopAuthEntity auth = shopAuthService.getByPath(menu.getMenuPath());
        if (auth != null) {
            shopAuthMapper.deleteById(auth);
            // 删除角色关联
            ShopRoleAuthEntity delReq = new ShopRoleAuthEntity();
            delReq.setAuthId(auth.getId());
            shopRoleAuthMapper.deleteByEntity(delReq);
        }
        // 查找子菜单
        ShopMenuEntity queryChildren = new ShopMenuEntity();
        queryChildren.setParentMenuId(req.getMenuId());
        List<ShopMenuEntity> list = shopMenuMapper.selectList(queryChildren);
        if (!list.isEmpty()) {
            for (ShopMenuEntity child : list) {
                DelMenuRequest childReq = new DelMenuRequest();
                childReq.setMenuId(child.getId());
                delMenu(childReq, loginUser);
            }
        }
    }

}
